News headline

1st half 2020

AU_timeline %>% 
  filter(date <= ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(100,100,280,320,550,20,100,550,720,150,
                            240,880,400,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/1.8), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 1st half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

2nd half 2020

AU_timeline %>% 
  filter(date > ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(50,100,280,420,550,720,100,550,720,150,
                            240,780,830,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/3), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 1st half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Full

AU_timeline %>% 
  # filter(date >= ymd(20200220)) %>% 
  arrange(date) %>% 
  add_row(date = ymd(20200120), event="") %>%
  # add_row(date = ymd(20200220), event="") %>%
  add_row(date = ymd(20200331), event="") %>%
  add_row(date = ymd(20200401), event="") %>%
  add_row(date = ymd(20200630), event="") %>%
  add_row(date = ymd(20200701), event="") %>%
  add_row(date = ymd(20200930), event="") %>%
  add_row(date = ymd(20201001), event="") %>%
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         point_position = 800 * nchar_scaled * (-1)^rowid,
         # point_position = c(100)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/2), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  facet_wrap(~facet_var, strip.position="top",
             ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Time series

Daily

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(notification_date) %>% 
  ggplot(aes(x=notification_date , y=n)) + 
  # geom_point() + 
  geom_line() + 
  ylab("Count of cases") + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD metro)") + 
  annotate("text", x=ymd(20200505), y=110, size=3.3, col="darkred", 
           label="1st outbreak \n (Bondi beach, \nSouth Eastern \nSydney)") + 
  annotate("text", x=ymd(20200815), y=30, size=3.3, col="darkred", 
           label="2nd outbreak \n (Liverpool, Western Sydney)") + 
  annotate("text", x=ymd(20210101), y=40, size=3.3, col="darkred", 
           label="3rd outbreak \n (Avalon beach, Northern Sydney)") + 
  ggl()

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(lhd_2010_name, notification_date) %>% 
  ggplot(aes(x=notification_date , y=n, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD)") + 
  ggl(lp = "right")

Cumulative

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Sydney (CBD)", 
                                lhd_2010_name)) %>% 
  # mutate(lhd_2010_name = ifelse(is.na(lhd_2010_name), "Unknown", lhd_2010_name)) %>%
  count(lhd_2010_name, notification_date) %>% 
  group_by(lhd_2010_name) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab = ifelse(notification_date == max(notification_date, na.rm=T), 
                      lhd_2010_name, NA)) %>% 
  
  ggplot(aes(x=days_since_first_case , y=accumulated_cases, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text_repel(aes(label=lab), size=4, hjust=-.1, min.segment.length = 10) + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Accumulated confirmed Covid-19 cases (SYD), by region") + 
  xlim(c(0,550)) +
  ggl(lp = "none") 

confirmed_cases %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Sydney (CBD)", 
                                lhd_2010_name)) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  # filter(lhd_2010_name %in% c("South Eastern Sydney", 
  #                          "Northern Sydney", 
  #                          "Western Sydney", 
  #                          "South Western Sydney", 
  #                          "Sydney") | is.na(lhd_2010_name)) %>% 
  count(lhd_2010_name, postcode, notification_date) %>% 
  group_by(lhd_2010_name, postcode) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab=ifelse(notification_date == max(notification_date), postcode, NA)) %>% 
  
  ggplot(aes(x=days_since_first_case , y=accumulated_cases, 
             group=postcode,
             col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text(aes(label=lab), size=3, hjust="outward") + 
  facet_wrap(~lhd_2010_name) +
  labs(subtitle = "Accumulated confirmed Covid-19 cases (Sydney), by postcode") + 
  xlim(c(0,550)) +
  ggl(lp = "none", )

Map

Looks like each postcode (POA) can only belong to one LGA, which is not the case for SA2

confirmed_cases %>% 
  distinct(postcode, lga_name19) %>% 
  count(postcode) %>% 
  summarise(max(n)) %>% 
  pull()
[1] 1

LGA

confirmed_cases %>% 
  filter(lga_name19 %in% SYD_LGA$LGA_NAME19) %>% 
  count(lga_name19, name="Total_cases") %>% 
  rename(LGA_NAME19 = lga_name19) %>% 
  mutate(LGA_NAME19 = fct_reorder(LGA_NAME19, Total_cases)) %>% 
  plot_map_TL(SYD_LGA, "LGA_NAME19", "Total_cases", 
           "Total Covid-19 cases by LGA (SYD Metro)", show_count = T)

POA

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           show_count = T, label_size = 2)

confirmed_cases %>% 
  filter(!(postcode %in% c(2026, 2145, 2170))) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD Metro), excluding top 3 POA", 
           show_count = T, label_size = 2)

Note

Northern Beaches has many postcodes which result in more diluted choropleth by POA.

confirmed_cases %>% 
  distinct(lga_name19, postcode) %>% 
  count(lga_name19, name="Number_of_postcodes") %>% 
  left_join(confirmed_cases %>% count(lga_name19, name="Total_cases"), 
            by="lga_name19") %>% 
  slice_max(n=30, order_by = Total_cases) %>% 
  gather(key, value, -lga_name19) %>% 
  ggplot(aes(x=reorder(lga_name19, value), y=value)) + 
  geom_col() + 
  facet_wrap(~key, scales = "free_x") + 
  coord_flip() + 
  xlab("") + ylab("") + 
  ggl()

Map overtime cumulative

By quarter

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>% 
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_cases", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme(legend.position = "top")

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_share", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme(legend.position = "top")

By week Mar-May 2020

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_cases", 
              "Total Covid-19 cases by POA (SYD Metro)", 
              return_obj="map") + 
  facet_wrap(~facet_var)

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_share", 
              "Total Covid-19 cases by POA (SYD Metro)", 
              return_obj="map") + 
  facet_wrap(~facet_var)

Distribution of share overtime

By quarter

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  ungroup() %>% 
  
  ggplot(aes(x=year_quarter, y=Accumulated_cases, 
             fill=Accumulated_cases > 50,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(year_quarter))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~year_quarter, nrow = 1) + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

By week

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=isoweek, y=Accumulated_cases, 
             fill=Accumulated_cases > 20,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggx(round, pbn=12) +
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(isoweek))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~isoweek, nrow = 3, labeller = "label_both") + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

Local POI

Public transport

confirmed_cases %>% 
    filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
    count(postcode, name="Total_cases") %>% 
    rename(POA_NAME16 = postcode) %>% 
    mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
    plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
                "Total Covid-19 cases by POA (SYD Metro), with public transport", 
                show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  ggc(c("deepskyblue", "red", "darkgreen", "orange")) + 
  guides(col=guide_legend(title="")) + 
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  coord_cartesian(xlim = c(150.7, 151.48), ylim = c(-34.1, -33.5)) +
  theme_void() +
  theme(legend.position = c(.9,.35))

Hospitals, Schools, Supermarket

bind_rows(
  SYD_shops %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
  SYD_supermarkets %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
  SYD_hospitals %>% select(Longitude, Latitude) %>% 
    rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
  rbind(SYD_sschools %>% select(Long, Lat),
        SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
) %>% 
  ggplot() +  
  geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
           aes(map_id = id), map = tidy(SYD_POA), 
           col="grey50", size=.2, fill="white") +
  geom_jitter(aes(x=Long, y=Lat, col=obj), size=.8, alpha=.5) + 
  stat_density2d(aes(x=Long, y=Lat, 
                     fill=..level.., alpha=..level.., col=obj),
                 binwidth = 1.2, geom="polygon", size=.23) + 
  facet_wrap(~obj) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "deepskyblue", "black", "darkgreen")) + 
  theme_void() +
  theme(legend.position = "none", 
        legend.title = element_blank(), 
        strip.text = element_text(size=15))

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
              "Total Covid-19 cases by POA (SYD Metro), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.25), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI combined

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
              "Total Covid-19 cases by POA (SYD Metro), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .1, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen", 
             "darkblue", "red", "darkgreen", "orange")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.4), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

LS0tDQp0aXRsZTogIlNZRCBDb3ZpZC0xOSBjYXNlcyBFREEiDQphdXRob3I6ICJUb255IExpdSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBzb3VyY2UoInV0aWxpdHkuUiIpDQpzb3VyY2UoIlJfZnVuY3Rpb25zLlIiKQ0Kc291cmNlKCJSX2RhdGFfcHJlcG9jZXNzaW5nLlIiKQ0KDQpvcHRpb25zKHNjaXBlbj05OTksIGV4cHJlc3Npb25zPTUwMDAwLCANCiAgICAgICAgRFQub3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDgsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFggPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9ucyA9IGMoJ2NvcHknLCAnY3N2JywgJ2V4Y2VsJywgJ3BkZicsICdwcmludCcpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0b1dpZHRoID0gVFJVRSkpIA0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFQsIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTQpDQprbml0cjo6b3B0c19rbml0JHNldChkZXYuYXJncyA9IGxpc3QodHlwZSA9ICJjYWlybyIpLCBwcm9ncmVzcz1GQUxTRSkNCmBgYA0KDQojIE5ld3MgaGVhZGxpbmUgDQojIyAxc3QgaGFsZiAyMDIwDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9DQpBVV90aW1lbGluZSAlPiUgDQogIGZpbHRlcihkYXRlIDw9IHltZCgyMDIwMDUxNSkpICU+JQ0KICBhcnJhbmdlKGRhdGUpICU+JSANCiAgIyBmaWx0ZXIobmNoYXIoZXZlbnQpIDwgMjMwKSAlPiUgDQogICMgZmlsdGVyKHJlZ2lvbiAhPSAiVklDIikgJT4lIA0KICBtdXRhdGUocm93aWQgPSBhcy5udW1lcmljKHJvd25hbWVzKC4pKSkgJT4lIA0KICBtdXRhdGUoZGF0ZV9nYXAgPSBhcy5udW1lcmljKGRhdGUtbGFnKGRhdGUpKSkgJT4lIA0KICBtdXRhdGUobmNoYXIgPSBuY2hhcihldmVudCksIA0KICAgICAgICAgbmNoYXJfc2NhbGVkID0gKG5jaGFyLW1pbihuY2hhcikpLyhtYXgobmNoYXIpLW1pbihuY2hhcikpLCANCiAgICAgICAgICMgcG9pbnRfcG9zaXRpb24gPSA3MDAgKiBuY2hhcl9zY2FsZWQgKiAoLTEpXnJvd2lkLA0KICAgICAgICAgcG9pbnRfcG9zaXRpb24gPSBjKDEwMCwxMDAsMjgwLDMyMCw1NTAsMjAsMTAwLDU1MCw3MjAsMTUwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDI0MCw4ODAsNDAwLDMwMCkqKC0xKV5yb3dpZA0KICAgICAgICAgKSAlPiUgDQogIG11dGF0ZShmYWNldF92YXIgPSBxdWFydGVyKGRhdGUsIHdpdGhfeWVhciA9IFQpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF0ZSwgeT0wKSkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgZ2VvbV9wb2ludChhZXMoY29sPXJlZ2lvbikpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4PWRhdGUsIHhlbmQ9ZGF0ZSwgY29sPXJlZ2lvbiwNCiAgICAgICAgICAgICAgICAgICB5PTAsIHllbmQ9cG9pbnRfcG9zaXRpb24pKSArDQogIGdlb21fcG9pbnQoYWVzKHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24pLCBzaGFwZT0xKSArDQogIGdlb21fdGV4dChhZXMoeT0tMTAsIA0KICAgICAgICAgICAgICAgIGxhYmVsPXBhc3RlMChkYXkoZGF0ZSksICIgIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vbnRoKGRhdGUsIGxhYmVsPVQpKSksIA0KICAgICAgICAgICAgYW5nbGU9MzAsIA0KICAgICAgICAgICAgdmp1c3Q9MSwgaGp1c3Q9MSkgKyANCiAgZ2VvbV9sYWJlbChhZXMobGFiZWw9c3RyX3dyYXAocGFzdGUwKGRhdGUsICI6ICIsIGV2ZW50KSwgbmNoYXIvMS44KSwgYWxwaGE9LjcsDQogICAgICAgICAgICAgICAgICMgZGlyZWN0aW9ucz0ieSIsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IEluZiwNCiAgICAgICAgICAgICAgICAgeD1kYXRlLCB5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uLCB2anVzdD0ib3V0d2FyZCIpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgDQogICAgICAgICAgICAgICBkYXRlX2xhYmVscyA9ICIlYiAlWSIpICsgDQogICMgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgIyAgICAgICAgICAgIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICAjIGNvb3JkX2ZsaXAoKSArDQogIHlsaW0oLTEyMDAsMTIwMCkgKyANCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJBVS9OU1cgQ292aWQtMTkgdGltZWxpbmUsIDFzdCBoYWxmIDIwMjAiKSArDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCiMjIDJuZCBoYWxmIDIwMjANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMn0NCkFVX3RpbWVsaW5lICU+JSANCiAgZmlsdGVyKGRhdGUgPiB5bWQoMjAyMDA1MTUpKSAlPiUNCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gNzAwICogbmNoYXJfc2NhbGVkICogKC0xKV5yb3dpZCwNCiAgICAgICAgIHBvaW50X3Bvc2l0aW9uID0gYyg1MCwxMDAsMjgwLDQyMCw1NTAsNzIwLDEwMCw1NTAsNzIwLDE1MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyNDAsNzgwLDgzMCwzMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzMpLCBhbHBoYT0uNywNCiAgICAgICAgICAgICAgICAgIyBkaXJlY3Rpb25zPSJ5IiwgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgICAgICAgICAgICAgICB4PWRhdGUsIHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24sIHZqdXN0PSJvdXR3YXJkIikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiViICVZIikgKyANCiAgIyBmYWNldF93cmFwKH5mYWNldF92YXIsIHN0cmlwLnBvc2l0aW9uPSJ0b3AiLA0KICAjICAgICAgICAgICAgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArDQogICMgY29vcmRfZmxpcCgpICsNCiAgeWxpbSgtMTIwMCwxMjAwKSArIA0KICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkFVL05TVyBDb3ZpZC0xOSB0aW1lbGluZSwgMXN0IGhhbGYgMjAyMCIpICsNCiAgdGhlbWVfdm9pZChiYXNlX3NpemUgPSAyMykgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICAjIHJlY3QgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLA0KICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAyLjMsIDAsIDIuMyksImNtIiksDQogICAgICAgICMgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOVUxMKQ0KICAgICAgICApDQpgYGANCg0KIyMgRnVsbA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTI1fQ0KQVVfdGltZWxpbmUgJT4lIA0KICAjIGZpbHRlcihkYXRlID49IHltZCgyMDIwMDIyMCkpICU+JSANCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDEyMCksIGV2ZW50PSIiKSAlPiUNCiAgIyBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDAyMjApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDMzMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwNDAxKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDA2MzApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDcwMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwOTMwKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDEwMDEpLCBldmVudD0iIikgJT4lDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICBwb2ludF9wb3NpdGlvbiA9IDgwMCAqIG5jaGFyX3NjYWxlZCAqICgtMSlecm93aWQsDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gYygxMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzIpLCBhbHBoYT0uNywNCiAgICAgICAgICAgICAgICAgIyBkaXJlY3Rpb25zPSJ5IiwgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgICAgICAgICAgICAgICB4PWRhdGUsIHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24sIHZqdXN0PSJvdXR3YXJkIikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiViICVZIikgKyANCiAgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgICAgICAgICAgICBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgIyBjb29yZF9mbGlwKCkgKw0KICB5bGltKC0xMjAwLDEyMDApICsgDQogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsgDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCiMgVGltZSBzZXJpZXMNCiMjIERhaWx5DQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQobm90aWZpY2F0aW9uX2RhdGUpICU+JSANCiAgZ2dwbG90KGFlcyh4PW5vdGlmaWNhdGlvbl9kYXRlICwgeT1uKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgeWxhYigiQ291bnQgb2YgY2FzZXMiKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkRhaWx5IG5ldyBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCBtZXRybykiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHg9eW1kKDIwMjAwNTA1KSwgeT0xMTAsIHNpemU9My4zLCBjb2w9ImRhcmtyZWQiLCANCiAgICAgICAgICAgbGFiZWw9IjFzdCBvdXRicmVhayBcbiAoQm9uZGkgYmVhY2gsIFxuU291dGggRWFzdGVybiBcblN5ZG5leSkiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHg9eW1kKDIwMjAwODE1KSwgeT0zMCwgc2l6ZT0zLjMsIGNvbD0iZGFya3JlZCIsIA0KICAgICAgICAgICBsYWJlbD0iMm5kIG91dGJyZWFrIFxuIChMaXZlcnBvb2wsIFdlc3Rlcm4gU3lkbmV5KSIpICsgDQogIGFubm90YXRlKCJ0ZXh0IiwgeD15bWQoMjAyMTAxMDEpLCB5PTQwLCBzaXplPTMuMywgY29sPSJkYXJrcmVkIiwgDQogICAgICAgICAgIGxhYmVsPSIzcmQgb3V0YnJlYWsgXG4gKEF2YWxvbiBiZWFjaCwgTm9ydGhlcm4gU3lkbmV5KSIpICsgDQogIGdnbCgpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChsaGRfMjAxMF9uYW1lLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bm90aWZpY2F0aW9uX2RhdGUgLCB5PW4sIGNvbD1saGRfMjAxMF9uYW1lKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgIyBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkRhaWx5IG5ldyBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCkiKSArIA0KICBnZ2wobHAgPSAicmlnaHQiKQ0KYGBgDQoNCiMjIEN1bXVsYXRpdmUNCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUobGhkXzIwMTBfbmFtZSA9IGlmZWxzZShsaGRfMjAxMF9uYW1lID09ICJTeWRuZXkiLCAiU3lkbmV5IChDQkQpIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxoZF8yMDEwX25hbWUpKSAlPiUgDQogICMgbXV0YXRlKGxoZF8yMDEwX25hbWUgPSBpZmVsc2UoaXMubmEobGhkXzIwMTBfbmFtZSksICJVbmtub3duIiwgbGhkXzIwMTBfbmFtZSkpICU+JQ0KICBjb3VudChsaGRfMjAxMF9uYW1lLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBncm91cF9ieShsaGRfMjAxMF9uYW1lKSAlPiUgDQogIG11dGF0ZShkYXlzX3NpbmNlX2ZpcnN0X2Nhc2UgPSBub3RpZmljYXRpb25fZGF0ZSAtIG1pbihub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgbXV0YXRlKGFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKG4pKSAlPiUgDQogIG11dGF0ZShsYWIgPSBpZmVsc2Uobm90aWZpY2F0aW9uX2RhdGUgPT0gbWF4KG5vdGlmaWNhdGlvbl9kYXRlLCBuYS5ybT1UKSwgDQogICAgICAgICAgICAgICAgICAgICAgbGhkXzIwMTBfbmFtZSwgTkEpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF5c19zaW5jZV9maXJzdF9jYXNlICwgeT1hY2N1bXVsYXRlZF9jYXNlcywgY29sPWxoZF8yMDEwX25hbWUpKSArIA0KICAjIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWxhYiksIHNpemU9NCwgaGp1c3Q9LS4xLCBtaW4uc2VnbWVudC5sZW5ndGggPSAxMCkgKyANCiAgIyBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkFjY3VtdWxhdGVkIGNvbmZpcm1lZCBDb3ZpZC0xOSBjYXNlcyAoU1lEKSwgYnkgcmVnaW9uIikgKyANCiAgeGxpbShjKDAsNTUwKSkgKw0KICBnZ2wobHAgPSAibm9uZSIpIA0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD02fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgbXV0YXRlKGxoZF8yMDEwX25hbWUgPSBpZmVsc2UobGhkXzIwMTBfbmFtZSA9PSAiU3lkbmV5IiwgIlN5ZG5leSAoQ0JEKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaGRfMjAxMF9uYW1lKSkgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICAjIGZpbHRlcihsaGRfMjAxMF9uYW1lICVpbiUgYygiU291dGggRWFzdGVybiBTeWRuZXkiLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vcnRoZXJuIFN5ZG5leSIsIA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VzdGVybiBTeWRuZXkiLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIlNvdXRoIFdlc3Rlcm4gU3lkbmV5IiwgDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICJTeWRuZXkiKSB8IGlzLm5hKGxoZF8yMDEwX25hbWUpKSAlPiUgDQogIGNvdW50KGxoZF8yMDEwX25hbWUsIHBvc3Rjb2RlLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBncm91cF9ieShsaGRfMjAxMF9uYW1lLCBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoZGF5c19zaW5jZV9maXJzdF9jYXNlID0gbm90aWZpY2F0aW9uX2RhdGUgLSBtaW4obm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIG11dGF0ZShhY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShuKSkgJT4lIA0KICBtdXRhdGUobGFiPWlmZWxzZShub3RpZmljYXRpb25fZGF0ZSA9PSBtYXgobm90aWZpY2F0aW9uX2RhdGUpLCBwb3N0Y29kZSwgTkEpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF5c19zaW5jZV9maXJzdF9jYXNlICwgeT1hY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgZ3JvdXA9cG9zdGNvZGUsDQogICAgICAgICAgICAgY29sPWxoZF8yMDEwX25hbWUpKSArIA0KICAjIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWxhYiksIHNpemU9MywgaGp1c3Q9Im91dHdhcmQiKSArIA0KICBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArDQogIGxhYnMoc3VidGl0bGUgPSAiQWNjdW11bGF0ZWQgY29uZmlybWVkIENvdmlkLTE5IGNhc2VzIChTeWRuZXkpLCBieSBwb3N0Y29kZSIpICsgDQogIHhsaW0oYygwLDU1MCkpICsNCiAgZ2dsKGxwID0gIm5vbmUiLCApDQpgYGANCg0KIyBNYXANCg0KTG9va3MgbGlrZSBlYWNoIHBvc3Rjb2RlIChQT0EpIGNhbiBvbmx5IGJlbG9uZyB0byBvbmUgTEdBLCB3aGljaCBpcyBub3QgdGhlIGNhc2UgZm9yIFNBMg0KDQpgYGB7cn0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGRpc3RpbmN0KHBvc3Rjb2RlLCBsZ2FfbmFtZTE5KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlKSAlPiUgDQogIHN1bW1hcmlzZShtYXgobikpICU+JSANCiAgcHVsbCgpDQpgYGANCg0KDQojIyBMR0ENCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGxnYV9uYW1lMTkgJWluJSBTWURfTEdBJExHQV9OQU1FMTkpICU+JSANCiAgY291bnQobGdhX25hbWUxOSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShMR0FfTkFNRTE5ID0gbGdhX25hbWUxOSkgJT4lIA0KICBtdXRhdGUoTEdBX05BTUUxOSA9IGZjdF9yZW9yZGVyKExHQV9OQU1FMTksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfTEdBLCAiTEdBX05BTUUxOSIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgTEdBIChTWUQgTWV0cm8pIiwgc2hvd19jb3VudCA9IFQpDQpgYGANCg0KIyMgUE9BDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMikNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKCEocG9zdGNvZGUgJWluJSBjKDIwMjYsIDIxNDUsIDIxNzApKSkgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pLCBleGNsdWRpbmcgdG9wIDMgUE9BIiwgDQogICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMikNCmBgYA0KDQojIyBOb3RlDQoNCk5vcnRoZXJuIEJlYWNoZXMgaGFzIG1hbnkgcG9zdGNvZGVzIHdoaWNoIHJlc3VsdCBpbiBtb3JlIGRpbHV0ZWQgY2hvcm9wbGV0aCBieSBQT0EuDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZGlzdGluY3QobGdhX25hbWUxOSwgcG9zdGNvZGUpICU+JSANCiAgY291bnQobGdhX25hbWUxOSwgbmFtZT0iTnVtYmVyX29mX3Bvc3Rjb2RlcyIpICU+JSANCiAgbGVmdF9qb2luKGNvbmZpcm1lZF9jYXNlcyAlPiUgY291bnQobGdhX25hbWUxOSwgbmFtZT0iVG90YWxfY2FzZXMiKSwgDQogICAgICAgICAgICBieT0ibGdhX25hbWUxOSIpICU+JSANCiAgc2xpY2VfbWF4KG49MzAsIG9yZGVyX2J5ID0gVG90YWxfY2FzZXMpICU+JSANCiAgZ2F0aGVyKGtleSwgdmFsdWUsIC1sZ2FfbmFtZTE5KSAlPiUgDQogIGdncGxvdChhZXMoeD1yZW9yZGVyKGxnYV9uYW1lMTksIHZhbHVlKSwgeT12YWx1ZSkpICsgDQogIGdlb21fY29sKCkgKyANCiAgZmFjZXRfd3JhcCh+a2V5LCBzY2FsZXMgPSAiZnJlZV94IikgKyANCiAgY29vcmRfZmxpcCgpICsgDQogIHhsYWIoIiIpICsgeWxhYigiIikgKyANCiAgZ2dsKCkNCmBgYA0KDQojIE1hcCBvdmVydGltZSBjdW11bGF0aXZlDQojIyBCeSBxdWFydGVyIHsudGFic2V0fQ0KIyMjIEFjY3VtdWxhdGVkIGNhc2VzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoeWVhcl9xdWFydGVyID0gcGFzdGUoeWVhcihub3RpZmljYXRpb25fZGF0ZSksICJRIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhcnRlcihub3RpZmljYXRpb25fZGF0ZSksIHNlcD0iLSIpKSAlPiUgDQogIGNvdW50KHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KHllYXJfcXVhcnRlcikgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCh5ZWFyX3F1YXJ0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoDQogICAgU1lEX1BPQVtTWURfUE9BJFBPQV9OQU1FMTYgJWluJSBhcy5jaGFyYWN0ZXIoDQogICAgICBjb25maXJtZWRfY2FzZXMkcG9zdGNvZGUpICxdLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfY2FzZXMiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNCiMjIyBBY2N1bXVsYXRlZCBzaGFyZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCh5ZWFyX3F1YXJ0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoDQogICAgU1lEX1BPQVtTWURfUE9BJFBPQV9OQU1FMTYgJWluJSBhcy5jaGFyYWN0ZXIoDQogICAgICBjb25maXJtZWRfY2FzZXMkcG9zdGNvZGUpICxdLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfc2hhcmUiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNCiMjIEJ5IHdlZWsgTWFyLU1heSAyMDIwIHsudGFic2V0fQ0KIyMjIEFjY3VtdWxhdGVkIGNhc2VzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTEwfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgZmlsdGVyKHllYXIobm90aWZpY2F0aW9uX2RhdGUpID09IDIwMjAsIA0KICAgICAgICAgIyBtb250aChub3RpZmljYXRpb25fZGF0ZSkgJWluJSAzOjUsIA0KICAgICAgICAgaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkgJWluJSAxMDoyMykgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoaXNvd2VlayA9IGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIGNvdW50KGlzb3dlZWssIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoaXNvd2VlaywgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoaXNvd2VlaykgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JQ0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKCJ3ZWVrICIsIGlzb3dlZWssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KFNZRF9QT0EsIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9jYXNlcyIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikNCmBgYA0KDQojIyMgQWNjdW11bGF0ZWQgc2hhcmUNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9MTB9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBmaWx0ZXIoeWVhcihub3RpZmljYXRpb25fZGF0ZSkgPT0gMjAyMCwgDQogICAgICAgICAjIG1vbnRoKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDM6NSwgDQogICAgICAgICBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDEwOjIzKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZShpc293ZWVrID0gaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgY291bnQoaXNvd2VlaywgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZShpc293ZWVrLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieShpc293ZWVrKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIG5hLnJtPVQpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KFNZRF9QT0EsIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9zaGFyZSIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikNCmBgYA0KDQojIERpc3RyaWJ1dGlvbiBvZiBzaGFyZSBvdmVydGltZQ0KIyMgQnkgcXVhcnRlcg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9My4zfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD15ZWFyX3F1YXJ0ZXIsIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiA1MCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Mi41fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1BY2N1bXVsYXRlZF9zaGFyZSwgZmlsbD1hcy5mYWN0b3IoeWVhcl9xdWFydGVyKSkpICsgDQogICMgZ2VvbV9kZW5zaXR5KCkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oKSArIA0KICBmYWNldF93cmFwKH55ZWFyX3F1YXJ0ZXIsIG5yb3cgPSAxKSArIA0KICB4bGltKDAsLjAzKSArIA0KICB5bGltKDAsNDApICsNCiAgZ2dsKCJub25lIikNCmBgYA0KDQojIyBCeSB3ZWVrDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zLjN9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBmaWx0ZXIoeWVhcihub3RpZmljYXRpb25fZGF0ZSkgPT0gMjAyMCwgDQogICAgICAgICAjIG1vbnRoKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDM6NSwgDQogICAgICAgICBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDEwOjIzKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZShpc293ZWVrID0gaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgY291bnQoaXNvd2VlaywgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZShpc293ZWVrLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieShpc293ZWVrKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpKSkgJT4lDQogIG11dGF0ZShmYWNldF92YXIgPSBwYXN0ZTAoIndlZWsgIiwgaXNvd2VlaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdW11bGF0ZWQ6ICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hKHN1bShBY2N1bXVsYXRlZF9jYXNlcykpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKCFpcy5uYShpc293ZWVrKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWlzb3dlZWssIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiAyMCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2d4KHJvdW5kLCBwYm49MTIpICsNCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NX0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGZpbHRlcih5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSA9PSAyMDIwLCANCiAgICAgICAgICMgbW9udGgobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMzo1LCANCiAgICAgICAgIGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMTA6MjMpICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGlzb3dlZWsgPSBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBjb3VudChpc293ZWVrLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKGlzb3dlZWssIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KGlzb3dlZWspICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzb3dlZWspKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9QWNjdW11bGF0ZWRfc2hhcmUsIGZpbGw9YXMuZmFjdG9yKGlzb3dlZWspKSkgKyANCiAgIyBnZW9tX2RlbnNpdHkoKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgpICsgDQogIGZhY2V0X3dyYXAofmlzb3dlZWssIG5yb3cgPSAzLCBsYWJlbGxlciA9ICJsYWJlbF9ib3RoIikgKyANCiAgeGxpbSgwLC4wMykgKyANCiAgeWxpbSgwLDQwKSArDQogIGdnbCgibm9uZSIpDQpgYGANCg0KIyBMb2NhbCBQT0kNCiMjIFB1YmxpYyB0cmFuc3BvcnQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogICAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogICAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICAgIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCBNZXRybyksIHdpdGggcHVibGljIHRyYW5zcG9ydCIsIA0KICAgICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMiwgcmV0dXJuX29iaiA9ICJtYXAiKSArDQogIA0KICAjIGdlb21fbWFwKGluaGVyaXQuYWVzID0gRkFMU0UsIGFscGhhPS44NSwNCiAgIyAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgIyAgICAgICAgICBjb2w9ImdyZXk1MCIsIHNpemU9LjMsIGZpbGw9IndoaXRlIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF90cmFpbnMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJUcmFpbiIsDQogICAgICAgICAgICAgICAgZ3JvdXAgPSBgUmFpbHdheSBsaW5lKHMpYCksDQogICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2ZlcnJpZXMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJGZXJyeSIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbGlnaHRyYWlscywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IkxpZ2h0cmFpbCIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbWV0cm8sIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJNZXRybyIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2djKGMoImRlZXBza3libHVlIiwgInJlZCIsICJkYXJrZ3JlZW4iLCAib3JhbmdlIikpICsgDQogIGd1aWRlcyhjb2w9Z3VpZGVfbGVnZW5kKHRpdGxlPSIiKSkgKyANCiAgZXhwYW5kX2xpbWl0cyh4ID0gdGlkeShTWURfUE9BKSRsb25nLCB5ID0gdGlkeShTWURfUE9BKSRsYXQpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDE1MC43LCAxNTEuNDgpLCB5bGltID0gYygtMzQuMSwgLTMzLjUpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjM1KSkNCmBgYA0KDQoNCiMjIEhvc3BpdGFscywgU2Nob29scywgU3VwZXJtYXJrZXQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9OH0NCmJpbmRfcm93cygNCiAgU1lEX3Nob3BzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTaG9wcGluZyBjZW50cmVzIiksIA0KICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTdXBlcm1hcmtldHMiKSwgDQogIFNZRF9ob3NwaXRhbHMgJT4lIHNlbGVjdChMb25naXR1ZGUsIExhdGl0dWRlKSAlPiUgDQogICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogIHJiaW5kKFNZRF9zc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCksDQogICAgICAgIFNZRF9wc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCkpICU+JSBtdXRhdGUob2JqID0gIlNjaG9vbHMiKQ0KKSAlPiUgDQogIGdncGxvdCgpICsgIA0KICBnZW9tX21hcChkYXRhID0gU1lEX1BPQSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWxwaGE9Ljg1LA0KICAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4yLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoYWVzKHg9TG9uZywgeT1MYXQsIGNvbD1vYmopLCBzaXplPS44LCBhbHBoYT0uNSkgKyANCiAgc3RhdF9kZW5zaXR5MmQoYWVzKHg9TG9uZywgeT1MYXQsIA0KICAgICAgICAgICAgICAgICAgICAgZmlsbD0uLmxldmVsLi4sIGFscGhhPS4ubGV2ZWwuLiwgY29sPW9iaiksDQogICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMS4yLCBnZW9tPSJwb2x5Z29uIiwgc2l6ZT0uMjMpICsgDQogIGZhY2V0X3dyYXAofm9iaikgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ3aGl0ZSIsIGhpZ2g9RENbN10pICsgDQogIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsLjMpKSArIA0KICBnZ2MoZmMgPSBjKCJkYXJrcmVkIiwgImRlZXBza3libHVlIiwgImJsYWNrIiwgImRhcmtncmVlbiIpKSArIA0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pLCB3aXRoIGhvc3BpdGFscywgc2Nob29scyAmIHN1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgbGFiZWxfc2l6ZSA9IDIsIHJldHVybl9vYmogPSAibWFwIikgKw0KICANCiAgIyBnZW9tX21hcChkYXRhID0gU1lEX1BPQSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWxwaGE9Ljg1LA0KICAjICAgICAgICAgIGFlcyhtYXBfaWQgPSBpZCksIG1hcCA9IHRpZHkoU1lEX1BPQSksIA0KICAjICAgICAgICAgIGNvbD0iZ3JleTUwIiwgc2l6ZT0uMywgZmlsbD0id2hpdGUiKSArDQogIGdlb21faml0dGVyKGRhdGEgPSBiaW5kX3Jvd3MoDQogICAgU1lEX3Nob3BzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlNob3BwaW5nIGNlbnRyZXMiKSwgDQogICAgU1lEX3N1cGVybWFya2V0cyAlPiUgc2VsZWN0KGxvbiwgbGF0KSAlPiUgDQogICAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTdXBlcm1hcmtldHMiKSwgDQogICAgU1lEX2hvc3BpdGFscyAlPiUgc2VsZWN0KExvbmdpdHVkZSwgTGF0aXR1ZGUpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gTG9uZ2l0dWRlLCBMYXQgPSBMYXRpdHVkZSkgJT4lIG11dGF0ZShvYmogPSAiSG9zcGl0YWxzIiksIA0KICAgIHJiaW5kKFNZRF9zc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCksDQogICAgICAgICAgU1lEX3BzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSkgJT4lIG11dGF0ZShvYmogPSAiU2Nob29scyIpDQogICksIA0KICBzaXplID0gMSwgYWxwaGEgPSAuMywgYWVzKHg9TG9uZywgeT1MYXQsY29sPW9iaikpICsNCiAgZXhwYW5kX2xpbWl0cyh4ID0gdGlkeShTWURfUE9BKSRsb25nLCB5ID0gdGlkeShTWURfUE9BKSRsYXQpICsNCiAgeGxpbSgxNTAuNywxNTEuNDgpICsgeWxpbSgtMzQuMSwtMzMuNSkgKw0KICAjIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ3aGl0ZSIsIGhpZ2g9RENbN10pICsgDQogIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsLjMpKSArIA0KICBnZ2MoZmMgPSBjKCJkYXJrcmVkIiwgImRhcmtibHVlIiwgImRhcmtvcmFuZ2UiLCAiZGFya2dyZWVuIikpICsgDQogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU9IlBPSSIpKSArIA0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC45LC4yNSksIA0KICAgICAgICAjIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSkpDQpgYGANCiMjIFBPSSBjb21iaW5lZA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQocG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX1BPQSwgIlBPQV9OQU1FMTYiLCAiVG90YWxfY2FzZXMiLCANCiAgICAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSwgd2l0aCBob3NwaXRhbHMsIHNjaG9vbHMgJiBzdXBlcm1hcmtldHMiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyLCByZXR1cm5fb2JqID0gIm1hcCIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfdHJhaW5zLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iVHJhaW4iLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gYFJhaWx3YXkgbGluZShzKWApLA0KICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9mZXJyaWVzLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iRmVycnkiKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2xpZ2h0cmFpbHMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJMaWdodHJhaWwiKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX21ldHJvLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iTWV0cm8iKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIA0KICAjIGdlb21fbWFwKGRhdGEgPSBTWURfUE9BLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBhbHBoYT0uODUsDQogICMgICAgICAgICAgYWVzKG1hcF9pZCA9IGlkKSwgbWFwID0gdGlkeShTWURfUE9BKSwgDQogICMgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4zLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGJpbmRfcm93cygNCiAgICBTWURfc2hvcHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU2hvcHBpbmcgY2VudHJlcyIpLCANCiAgICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlN1cGVybWFya2V0cyIpLCANCiAgICBTWURfaG9zcGl0YWxzICU+JSBzZWxlY3QoTG9uZ2l0dWRlLCBMYXRpdHVkZSkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogICAgcmJpbmQoU1lEX3NzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSwNCiAgICAgICAgICBTWURfcHNjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpKSAlPiUgbXV0YXRlKG9iaiA9ICJTY2hvb2xzIikNCiAgKSwgDQogIHNpemUgPSAxLCBhbHBoYSA9IC4xLCBhZXMoeD1Mb25nLCB5PUxhdCxjb2w9b2JqKSkgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogICMgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD1EQ1s3XSkgKyANCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMCwuMykpICsgDQogIGdnYyhmYyA9IGMoImRhcmtyZWQiLCAiZGFya2JsdWUiLCAiZGFya29yYW5nZSIsICJkYXJrZ3JlZW4iLCANCiAgICAgICAgICAgICAiZGFya2JsdWUiLCAicmVkIiwgImRhcmtncmVlbiIsICJvcmFuZ2UiKSkgKyANCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0zKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iUE9JIikpICsgDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjQpLCANCiAgICAgICAgIyBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==